/*
 * ListaEnlazada.cpp
 *
 *  Created on: Apr 29, 2012
 *      Author: Nico
 */

#ifndef LISTAENLAZADA_H_
#define LISTAENLAZADA_H_

#include "ListaEnlazada.h"

/* Metodos protegidos */
template <class Generic>
Nodo<Generic>* ListaEnlazada<Generic>::_last_nodo(){
	if( this->length == 0 ) return this->prox;
	Nodo<Generic>* nodoActual = this->prox;
	while(nodoActual->has_next()){
		nodoActual->get_next(&nodoActual);
	}
	return nodoActual;
}

template <class Generic>
int ListaEnlazada<Generic>::_index_nodo(int index , Nodo<Generic>** unNodo){
	
	unsigned int indexu = (unsigned int) index; // Fix para warning de comparacion entre unsigned int y signed int
	
	if( this->length == 0 ) return -1;
	if( indexu < 0 ) return -2;
	if( indexu >= this->length ) return -3;
	
	unsigned int i = 0;
	*unNodo = this->prox;
	while( i++ < indexu ){
		(*unNodo)->get_next(unNodo);
	}
	return 0;
}

/* Metodos publicos */
template <class Generic>
ListaEnlazada<Generic>::ListaEnlazada(){
	this->length = 0;
	this->prox = new Nodo<Generic>;
}

template <class Generic>
ListaEnlazada<Generic>::~ListaEnlazada(){
	
	Nodo<Generic>* nodoAnterior = this->prox;
	Nodo<Generic>* nodoSiguiente;
	unsigned int i;
	for( i=0 ; i < this->length ; i++ ){
		nodoAnterior->get_next(&nodoSiguiente);
		delete nodoAnterior;
		nodoAnterior = nodoSiguiente;
	}
	
	this->length = NULL;
}

template <class Generic>
void ListaEnlazada<Generic>::print(){
	Nodo<Generic>* nodoActual = this->prox;
	
	printf( "[" );
	
	unsigned int i;
	Generic value;
	for( i=0 ; i < (this->length - 1) ; i++ ){
		nodoActual->get_value(value);
		nodoActual->get_next(&nodoActual);
		printf("  %d  ," , value );
		
	}
	nodoActual->get_value(value);
	printf("  %d  " , value );
	
	printf( "]\n" );
}

template <class Generic>
void ListaEnlazada<Generic>::print_full(){
	Nodo<Generic>* nodoActual = this->prox;
	
	unsigned int i;
	Generic val;
	for( i=0 ; i < (this->length) ; i++ ){
		nodoActual->get_value(val);
		nodoActual->get_next(&nodoActual);
		cout<< "Lista[" << i << "] = " << val << endl;
	}
}

template <class Generic>
unsigned int ListaEnlazada<Generic>::get_length(){
	return this->length;
}

template <class Generic>
int ListaEnlazada<Generic>::append(Generic dato){
	
	Nodo<Generic>* ultimoNodo = this->_last_nodo();

	Nodo<Generic>* nuevoNodo = new Nodo<Generic>;
	nuevoNodo->set_value(dato);
	
	if( this->length == 0 ){
		delete this->prox;
		this->prox = nuevoNodo;
	}else{
		ultimoNodo->set_next(nuevoNodo);
	}
	
	this->length++;
	
	return 0;
}

template <class Generic>
int ListaEnlazada<Generic>::index(int index , Generic &value){
	

	Nodo<Generic>* unNodo;
	int condition_code = this->_index_nodo(index , &unNodo);
	
	if(condition_code < 0) return condition_code;
	
	unNodo->get_value(value);
	
	return 0;
}

template <class Generic>
int ListaEnlazada<Generic>::deleteIndex(int index){
	
	Nodo<Generic>* nodoActual;
	int condition_code = this->_index_nodo(index , &nodoActual);
	
	if(condition_code < 0) return condition_code;
	
	if( index == 0 ){
		this->prox->get_next(&this->prox);
	}else{
		Nodo<Generic>* nodoAnterior;
		int condition_code = this->_index_nodo(index-1 , &nodoAnterior);
		if(condition_code < 0) return condition_code;
		
		Nodo<Generic>* nodoSiguiente;
		nodoActual->get_next(&nodoSiguiente);
		
		nodoAnterior->set_next(nodoSiguiente);
		
		delete nodoActual;
	}
	
	this->length--;
	
	return 0;
}

template <class Generic>
int ListaEnlazada<Generic>::set(int index , Generic newValue){
	Nodo<Generic>* nodo;
	this->_index_nodo(index, &nodo);
	nodo->set_value(newValue);
	return 0;
}

template <class Generic>
Iterador<Generic>* ListaEnlazada<Generic>::get_iterador(){
	Iterador<Generic>* iterador = new Iterador<Generic>(this,this->prox);
	return iterador;
}

#endif /* LISTAENLAZADA_H_ */
